Skip to content

Fix Symbol.info remapping in TreeTypeMap #23432

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 27, 2025

Conversation

jchyb
Copy link
Contributor

@jchyb jchyb commented Jun 26, 2025

Fixes #23279

The issue stems from the fact that in Inlining, when reassigning the owners the inlinined argument (with arg.changeOwner in paramBindingDef), due to a quirk in TypeTreeMap (fixed here), the info field of a xa symbol would not be completely remapped, referencing a TypeRef likedefn(correct Symbol, with newly remapped owner).Lifecycle(old and incorrect, with previous owner). This info would then be used in typedValDef in erasure to reassign the ValDef TypeTree, referencing the old, incorrect Symbol from now on. After that, LambdaLift would remap the denotations of class and object Symbols found in the tree, while moving their trees outside of methods. Since no class or object definition referenced the old Symbol, that one would not get remapped. So by the time we generated backend code, the ValDef TypeTree would reference an incorrect location that no longer existed, causing the runtime error later.

The reason why the TypeTreeMap was incorrect was because in situation like this:

  final lazy module val lifecycle#7793: lifecycle#7794 = new lifecycle#7794()
  final module class lifecycle#7794() extends Object#740() {
    this: lifecycle#7793.type =>
    final lazy module val Lifecycle#7799:
      Test2$package#3202.lifecycle#7793.Lifecycle#7800 =
      new Test2$package#3202.lifecycle#7793.Lifecycle#7800()
    final module class Lifecycle#7800() extends Object#740() {
      this: lifecycle#7794.this#7794.Lifecycle#7799.type =>}
  }
  final lazy module val defn#7795: defn#7796 = new defn#7796()
  final module class defn#7796() extends Object#740() { this: defn#7795.type =>
    val Lifecycle#7805: lifecycle#7793.Lifecycle#7799.type =
      lifecycle#7793.Lifecycle#7799
  }
  val xa#7797: defn#7795.Lifecycle#7805.type = defn#7795.Lifecycle#7805
  ()

The remapper would first copy and replace the outermost symbols (including lifecycle#7793, lifecycle#7794, defn#7795, defn#7796, xa#7797), and then separately go through classes definitions. Now we also remap info the second time, with the newly mapped nested Symbols.

Previously, the map would first copy and remap the outermost symbols,
then inner declarations, then ddeclarations of those declarations etc.,
so if an outer symbol referred to a more nested one, that reference was
not remapped, causing issues later.
Copy link
Contributor

@odersky odersky left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch!

@odersky odersky merged commit d995b33 into scala:main Jun 27, 2025
29 checks passed
@odersky odersky deleted the fix-i23279-fix-tree-type-map branch June 27, 2025 14:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Trivial inline identity function causes runtime NoClassDefFound error in resulting code
3 participants